package com.gbase8c.dmt.db.opengauss;

import com.gbase8c.dmt.db.object.IndexObject;
import com.gbase8c.dmt.model.migration.config.Task;
import com.gbase8c.dmt.model.migration.dto.DataSourceDto;
import com.gbase8c.dmt.model.migration.dto.IndexDto;
import com.gbase8c.dmt.model.migration.dto.PartitionInfoDto;
import com.gbase8c.dmt.model.migration.wrapper.KeywordsWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
public class IndexObjectImpl extends MetaImpl implements IndexObject {

    public IndexObjectImpl(DataSourceDto dataSourceDto) {
        super(dataSourceDto);
    }

    @Override
    public List<String> getNames(Map<String, Object> params) {
        return null;
    }

    @Override
    public IndexDto get(String name, Map<String, Object> params) {
        return null;
    }

    @Override
    public IndexDto convert(IndexDto indexDto, Map<String, Object> params) {
        if (StringUtils.isBlank(indexDto.getTarMethod())){
            String srcMethod = indexDto.getSrcMethod().toLowerCase();
            // 校验是否是8c能识别的accessMethod,默认写入bree
//            AccessMethod accessMethod = AccessMethod.valueOf(srcMethod);
            Set<String> accessMethodNames = Sets.newHashSet(AccessMethod.btree.name(),
                    AccessMethod.hash.name(),
                    AccessMethod.gist.name(),
                    AccessMethod.spgist.name(),
                    AccessMethod.gin.name(),
                    AccessMethod.ubtree.name(),
                    AccessMethod.psort.name());
            String tarMethod = accessMethodNames.contains(srcMethod) ? srcMethod : AccessMethod.btree.name();
            indexDto.setTarMethod(tarMethod);
        }else {
            indexDto.setTarMethod(AccessMethod.btree.name());
        }

        boolean preserveCase = indexDto.getTask().getMigrateConfig().isPreserveCase();
        Task task = indexDto.getTask();
        KeywordsWrapper keywordsWrapper = new KeywordsWrapper(task.getKeywordsConfig());
        String tarTableName = keywordsWrapper.getTableName(indexDto.getSchema(), indexDto.getTableName(), preserveCase);

        for (IndexDto.IndexColumnDto indexColumnDto : indexDto.getIndexColumns()) {
            String tarColumnName = keywordsWrapper.getColumnName(indexDto.getSchema(), indexDto.getTableName(),
                    indexColumnDto.getColumnName(),preserveCase);
            indexColumnDto.setTarColumnName(tarColumnName);
        }

        indexDto.setTarTableName(tarTableName);
        indexDto.setIsMigration(Boolean.TRUE);
        indexDto.setConvertible(Boolean.TRUE);
        return indexDto;
    }

    @Override
    public String sql(IndexDto indexDto, Map<String, Object> params) {
        StringBuilder sqlBuilder = new StringBuilder();
//                Boolean containPk = checkContainPk(pkList,indexDto.getIndexColumns());
//                if (!containPk){
        String tarSchema = indexDto.getTarSchema();
        String indexName = indexDto.getName();
        // todo
        String tableName = indexDto.getTableName();
        String tarTableName = indexDto.getTarTableName();
        boolean preserveCase = indexDto.getTask().getMigrateConfig().isPreserveCase();
        boolean isPartIndex = indexDto.getIsPartIndex();
        String indexType = indexDto.getSrcMethod();
        //如果索引名和表名相同，会造成8c里建不上和表名同名索引，加后缀_8c，结果比对时去除。
//        if (indexName.equalsIgnoreCase(indexDto.getTableName())){
//            indexName = indexName+"_8c";
//        }
        String tarIndexName = tableName + "_" + indexName;

        List<IndexDto.IndexColumnDto> indexColumnDtos = indexDto.getIndexColumns();
        List<String> indexColNames = Lists.newArrayList();
        for (IndexDto.IndexColumnDto indexColumnDto : indexColumnDtos) {
            String collation = null ;
            String tarColumnName = indexColumnDto.getTarColumnName();
            if (!StringUtils.isBlank(indexColumnDto.getCollation())) {
                collation = indexColumnDto.getCollation();
                if (collation.equals("D")) {
                    indexColNames.add(wrap(tarColumnName, preserveCase) + " DESC ");
                }
                else {
                    indexColNames.add(wrap(tarColumnName, preserveCase));
                }
            } else {
                indexColNames.add(wrap(tarColumnName, preserveCase));
            }
        }

        if (indexType.equals("NORMAL/REV")) {
            List<String> tempColumn = Lists.newArrayList();
            indexColNames.stream().forEach(str -> {
                str = "reverse(" + str + ")";
                tempColumn.add(str);
            });
            indexColNames = tempColumn;
        }

        String tableSpaceName = null;
        if (indexDto.getIsToTableSpace() != null && indexDto.getIsToTableSpace()){
            tableSpaceName = indexDto.getTableSpaceName();
        }

        String indexMethod = indexDto.getTarMethod();

        sqlBuilder.append("CREATE");
        Boolean uni = indexDto.isIndexUnique();
        if (uni) {
            sqlBuilder.append(" UNIQUE ");
        }
        sqlBuilder.append(" INDEX ")
                .append(wrap(tarIndexName, preserveCase))
                .append(" ").append(" ON ")
                .append(wrap(tarSchema, true))
                .append(".").append(wrap(tarTableName, preserveCase));
        if (isPartIndex) {
            if (!StringUtils.isBlank(indexDto.getPartIndexKind())) {
                String kind = indexDto.getPartIndexKind();
                String indColumns = null;
                if (!StringUtils.isBlank(indexDto.getPartIndexColumn())); {
                    indColumns = indexDto.getPartIndexColumn();
                }
                if (kind.equals("I")) {
                    sqlBuilder.append(" (")
                            .append(indColumns).append(")")
                            .append(" global ");
                } else if (kind.equals("i")) {
                    sqlBuilder.append(" (")
                            .append(indColumns).append(")")
                            .append(" local ");
                    if (CollectionUtils.isNotEmpty(indexDto.getPartitionInfos())) {
                        sqlBuilder.append("(");
                        StringBuilder sb = new StringBuilder();
                        for (PartitionInfoDto partitionInfoDto:indexDto.getPartitionInfos()){
                            sb.append("partition ").append(partitionInfoDto.getPartitionName());
                            sb.append(",");
                        }
                        String result = sb.substring(0,sb.length()-1);
                        sqlBuilder.append(result).append(")");
                    }
                }
            }
        } else if(indexMethod.equals(AccessMethod.gin.name())){
            if (!StringUtils.isBlank(indexDto.getIndexDef())) {
                String indexDef = indexDto.getIndexDef();
                sqlBuilder.append(" USING ").append(indexDto.getTarMethod()).append(" ")
                        .append("(").append(indexDef).append(")");
            }
        } else {
            sqlBuilder.append(" USING ")
                    .append(indexDto.getTarMethod()).append(" (")
                    .append(StringUtils.join(indexColNames, ",")).append(")");
        }

        if (tableSpaceName != null){
            sqlBuilder.append(" tablespace ").append(wrap(tableSpaceName, preserveCase)).append(";");
        }else {
            sqlBuilder.append(";");
        }
//        //判断索引是否需要转换
//        if (indexDto.getIsMigration()){
//            resultSqlList.add(sqlBuilder.toString());
//        }
        indexDto.setTarSql(sqlBuilder.toString());
        log.info(sqlBuilder.toString());
        return sqlBuilder.toString();
    }

    @Override
    public List<IndexDto> getIndexDtos(String schema) {
        return Lists.newArrayList();
    }

    @Override
    public List<IndexDto> getIndexDtos(String schema, String table) {
        return Lists.newArrayList();
    }

    @Override
    public IndexDto getIndexDto(String schema, IndexDto indexDto, List<String> tableSpaceNames) {
        return null;
    }

    public enum AccessMethod {
        btree,hash,gist,spgist,gin,ubtree,psort;
    }

}
